/*
 * Basado en el libro de Duane A. Bailey, "Java Structures", pág. 284
 */
package Hoja6;

/**
 *
 * @param <E> 
 * @author María Fernanda Martínez
 */
public class BinaryTree <E> {
    
    protected E val; // valor asociado al nodo
    protected BinaryTree<E> parent; // padre del nodo
    protected BinaryTree<E> left,right; // hijos del nodo
    
    /**
     * Nombre: BinaryTree
     * Descripción: Constructor de la clase
     * Pre: no hay
     * Post: genera un nodo vacío
     * No hay parámetros ni valor de retorno
     */
    public BinaryTree(){
        val = null;
        parent = null; left = right = this;
    }
    
    /**
     * Nombre: BinaryTree
     * Descripción: Constructor de la clase con valor inicial
     * Pre: value no es null
     * Post: nuevo árbol con un valor referenciando a dos subárboles vacíos.
     * No hay valor de retorno
     * @param value
     */
    public BinaryTree(E value){
        val = value;
        right = left = new BinaryTree<E>();
        setLeft(left);
        setRight(right);
    }
    
    /**
     * Nombre: BinaryTree
     * Descripción: Constructor de la clase con un valor inicial e hijos
     * Pre: value no es null
     * Post: árbol con valor y dos subárboles
     * No hay valor de retorno
     * @param value
     * @param left 
     * @param right
     */
    public BinaryTree(E value, BinaryTree<E> left, BinaryTree<E> right){
        val = value;
        if (left == null) { left = new BinaryTree<E>(); }
        setLeft(left);
        if (right == null) { right = new BinaryTree<E>(); }
        setRight(right);
    }
    
    /**
     * Nombre: left
     * Descripción: acceder al valor de left
     * Pre: no hay
     * Post: regresa referencia a subárbol izquierdo
     * No hay parámetro
     * @return
     */
    public BinaryTree<E> left(){
        return left;
    }
    
    /**
     * Nombre: right
     * Descripción: acceder al valor de right
     * Pre: no hay
     * Post: regresa referencia a subárbol derecho
     * No hay parámetro
     * @return
     */
    public BinaryTree<E> right(){
        return right;
    }
    
    /**
     * Nombre: parent
     * Descripción: acceder al valor de parent
     * Pre: no hay
     * Post: regresa referencia a un nodo padre, o null
     * No hay parámetro
     * @return
     */
    public BinaryTree<E> parent(){
        return parent;
    }
    
    /**
     * Nombre: setLeft
     * Descripción: asigna nuevo valor a left
     * Pre: padre de newLeft no es null
     * Post: asigna newLeft a left
     * No hay valor de retorno
     * @param newLeft
     */
    public void setLeft(BinaryTree<E> newLeft){
        if (isEmpty()) return;
        if (left != null && left.parent() == this) left.setParent(null);
        left = newLeft;
        left.setParent(this);
    }
    
    /**
     * Nombre: setRight
     * Descripción: asigna nuevo valor a right
     * Pre: padre de newRight no es null
     * Post: asigna newRight a right
     * No hay valor de retorno
     * @param newRight
     */
    public void setRight(BinaryTree<E> newRight){
        if (isEmpty()) return;
        if (right != null && right.parent() == this) right.setParent(null);
        right = newRight;
        right.setParent(this);
    }
    
    /**
     * Nombre: setParent
     * Descripción: asigna nuevo valor a parent
     * Pre: no hay
     * Post: newParent se convierte en parent
     * No hay valor de retorno
     * @param newParent
     */
    protected void setParent(BinaryTree<E> newParent){
        if (!isEmpty()) {
            parent = newParent;
        }
    }
    
    /**
     * Nombre: value
     * Descripción: acceder al valor de val
     * Pre: no hay
     * Post: regresa valor asociado al nodo
     * No hay parámetros
     * @return
     */
    public E value(){
        return val;
    }
    
    /**
     * Nombre: setValue
     * Descripción: asigna nuevo valor a val
     * Pre: value no es null
     * Post: asigna el valor asociado al nodo.
     * No hay valor de retorno
     * @param value
     */
    public void setValue(E value){
        val = value;
    }
    
    /**
     * Nombre: isEmpty
     * Descripción: verifica si el árbol está vacío
     * Pre: no hay
     * Post: regresa true si el árbol está vacío
     * @return
     */
    public boolean isEmpty() {
        return val==null&&parent==null&&right==this&&left==this;
    }
}
